﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media.Animation;
using System.Windows;
using System.Windows.Controls;
using GraphosData;
using System.Windows.Threading;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Data;
using System.ComponentModel;
using System.Windows.Media.Imaging;

namespace GraphosControls
{
    

	public class VisualNode : Control, INotifyPropertyChanged
	{
        public VisualNode()
        {
            DataContext = this;
            Node = new Node(new Person());
            ResetKeneticValues();
        }

		public VisualNode(Node node)
		{
			DataContext = this;
			Node = node;
            ResetKeneticValues();
		}

        #region Kenetic Properties

        /// <summary>
        /// Gets or sets the velocity of this node
        /// </summary>
        public Vector Velocity { get; set; }
      

        /// <summary>
        /// Gets or sets the net force for this node
        /// </summary>
        public Vector NetForce { get; set; }

        /// <summary>
        /// Gets or sets the charge for this node
        /// </summary>
        public double Charge { get; set; }

        /// <summary>
        /// Resets all the kenetic node values for positioning
        /// </summary>
        public void ResetKeneticValues()
        {
            Velocity = new Vector(0, 0);
            NetForce = new Vector(0, 0);
        } 

        #endregion

		#region Dependency Properties

		/// <summary>
		/// Gets or sets a boolean identifying if this node is selected or not 
		/// </summary>
		public bool IsRootNode
		{
            get { return (bool)GetValue(IsRootNodeProperty); }
            set { SetValue(IsRootNodeProperty, value); }
		}
        public static readonly DependencyProperty IsRootNodeProperty =
              DependencyProperty.Register("IsRootNode", typeof(bool), typeof(VisualNode), 
              new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.None, 
                  new PropertyChangedCallback(OnIsRootNodeChanged)));
        private static void OnIsRootNodeChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            (sender as VisualNode).UpdateStyles();
        }

        public bool IsGroupSelected
        {
            get { return (bool)GetValue(IsGroupSelectedProperty); }
            set { SetValue(IsGroupSelectedProperty, value); }
        }
        public static readonly DependencyProperty IsGroupSelectedProperty =
            DependencyProperty.Register("IsGroupSelected", typeof(bool), typeof(VisualNode), 
            new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.None));

        public Point Position
        {
            get { return (Point)GetValue(PositionProperty); }
            set { SetValue(PositionProperty, value); }
        }
        public static readonly DependencyProperty PositionProperty =
            DependencyProperty.Register("Position", typeof(Point), typeof(VisualNode),
            new FrameworkPropertyMetadata(new Point(0, 0), FrameworkPropertyMetadataOptions.None, 
                new PropertyChangedCallback(OnPositionChanged)));
        private static void OnPositionChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            VisualNode node = sender as VisualNode;
            Point point = (Point)args.NewValue;
            Canvas.SetLeft(node, point.X - node.Center.X);
            Canvas.SetTop(node, point.Y - node.Center.Y);
        }

		#endregion

		#region Properties

		/// <summary>
		/// Gets the node associated with this VisualNode
		/// </summary>
		public Node Node { get; private set; }

		/// <summary>
		/// Gets or sets the VisualNodes adjacent to this node which are in common with the selected node
		/// </summary>
		public IList<VisualNode> AdjacentVisualNodes { get; set; }
        public Point Center { get; private set; }
        public Brush VisualNodeFillBrush
        {
            get { return GetBrushResource("Fill"); }
        }
        public Brush VisualNodeStrokeBrush
        {
            get { return GetBrushResource("Stroke"); }
        }
        public Brush VisualNodeForegroundBrush
        {
            get { return GetBrushResource("Foreground"); }
        }
        private string StateString
        {
            get
            {
                string state = string.Empty;
                state += IsRootNode ? "Selected" : "";
                state += IsMouseCaptured ? "Captured" : "";
                return state;
            }
        }

		#endregion

		#region Overrides

		protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
		{
			// keep the center point up to date when the node changes size
			Center = new Point(sizeInfo.NewSize.Width / 2, sizeInfo.NewSize.Height / 2);
			base.OnRenderSizeChanged(sizeInfo);
		}
        
		protected override void OnInitialized(EventArgs e)
		{
			// set the node style
			Style = (Style)TryFindResource("VisualNodeStyle");
            UpdateStyles();
			base.OnInitialized(e);
		}
        protected override void OnIsMouseCapturedChanged(DependencyPropertyChangedEventArgs e)
        {
            base.OnIsMouseCapturedChanged(e);
            UpdateStyles();
        }
		public override string ToString()
		{
			return string.Format("VisualNode: {0}", Node.Person);
        }
        #endregion

        public void UpdateStyles()
        {
            OnPropertyChanged("VisualNodeFillBrush");
            OnPropertyChanged("VisualNodeStrokeBrush");
            OnPropertyChanged("VisualNodeForegroundBrush");
        }
        private Brush GetBrushResource(string type)
        {
            string name = string.Format("{0}{1}{2}Brush",
                Node.Person.Gender.ToString(),
                StateString,
                type);

            return (Brush)TryFindResource(name);
        }


        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string info)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(info));
        }

        #endregion
    }
}